#include "Node.h"
#include <cstdio>

#include <math.h>

using namespace std;

Node::Node(Image* image) {
    set_father(NULL);
    this->set_leaf(image);
}

Node::Node(Image* image, int id) {
    set_father(NULL);
    this->set_leaf(image);
    this->set_id(id);
}

Node::Node(Node* left, Orientation orientation, Node* right) {
    set_father(NULL);
    this->set_bissection(left, orientation, right);
}

Node::Node(Node* node) {
    set_father(node->get_father());
    if(node->is_leaf()) {
        set_leaf(new Image(node->get_image()));
        set_id(node->get_id());
    } else {
        set_bissection(new Node(node->get_left()), node->get_orientation(), new Node(node->get_right()));
    }
}

void Node::set_bissection(Node* left, Orientation orientation, Node* right) {
    this->set_left(left);
    this->set_right(right);
    this->orientation = orientation;
    this->type = BISS;
}

void Node::set_leaf(Image* imagem) {
    this->image = imagem;
    this->type = LEAF;
}

Image* Node::get_image() {
    return this->image;
}

Node* Node::get_left() {
    return this->left;
}

Node* Node::get_right() {
    return this->right;
}

Orientation Node::get_orientation() {
    return this->orientation;
}

Type Node::get_type() {
    return this->type;
}

int Node::get_id() {
    return this->id;
}

void Node::set_id(int id) {
    this->id = id;
}

void Node::enumerate() {
    
}

double Node::sum_image_areas() {
    return is_leaf() ? get_image()->get_area() : (get_left()->sum_image_areas() + get_right()->sum_image_areas());
}

double Node::sum_relative_areas() {
    return is_leaf() ? get_image()->get_relative_area() : (get_left()->sum_relative_areas() + get_right()->sum_relative_areas());
}

void Node::set_left(Node* left) {
    this->left = left;
    left->set_father(this);
}

void Node::set_right(Node* right) {
    this->right = right;
    right->set_father(this);
}

Node* Node::get_father() {
    return this->father;
}

void Node::set_father(Node* father) {
    this->father = father;
}

/*void Node::copy(Node* raiz) {
    if(raiz) {
        if(raiz->getType() == BISS) {
            Node* left = new Node(raiz->getLeft()->getType());
            Node* right = new Node(raiz->getRight()->getType());
            left->copy(raiz->getLeft());
            right->copy(raiz->getRight());
            
            this->setBissection(left, raiz->getOrientation(), right);
        } else {
            Image* img = raiz->getImage();
            this->setLeaf(new Image(img->getWidth(), img->getHeight(), img->getPriority()));
        }
    }
}*/

double max(double a, double b) {
    return a > b ? a : b;
}

int Node::get_height(int alpha, int beta) {
    if(this->get_type() == BISS) {
        if(this->get_orientation() == HORIZONTAL) {
            return this->get_left()->get_height(alpha, beta) + this->get_right()->get_height(alpha, beta) + alpha;
        } else {
            return max(this->get_left()->get_height(alpha, beta), this->get_right()->get_height(alpha, beta));
        }
    } else {
        return this->get_image()->get_height() + 2*beta;
    }
}

int Node::get_width(int alpha, int beta) {
    if(this->get_type() == BISS) {
        if(this->get_orientation() == HORIZONTAL) {
            return max(this->get_left()->get_width(alpha, beta), this->get_right()->get_width(alpha, beta));
        } else {
            return this->get_left()->get_width(alpha, beta) + this->get_right()->get_width(alpha, beta) + alpha;
        }
    } else {
        return this->get_image()->get_width() + 2*beta;
    }
}

int Node::get_area(int alpha, int beta) {
    return get_height(alpha, beta) * get_width(alpha, beta);
}

bool Node::is_leaf() {
    return this->get_type() == LEAF;
}

void Node::get_leafs(vector<Node*> *leafs) {
    if(is_leaf())
        leafs->push_back(this);
    else {
        get_left()->get_leafs(leafs);
        get_right()->get_leafs(leafs);
    }
}

int Node::sum_filled_area(int alpha, int beta) {
    int area = 0;
    if(is_leaf())
        area = get_width(alpha, beta) * get_height(alpha, beta);
    else
        if(get_orientation() == HORIZONTAL)
            area = alpha * get_width(alpha, beta) + get_left()->sum_filled_area(alpha, beta) + get_right()->sum_filled_area(alpha, beta);
        else
            area = alpha * get_height(alpha, beta) + get_left()->sum_filled_area(alpha, beta) + get_right()->sum_filled_area(alpha, beta);
    return area;
}